﻿using System;
using System.Collections.Generic;

namespace Sigil.Impl
{
	internal class VerificationResult
	{
		public Boolean Success { get; private set; }

		public Stack<List<TypeOnStack>> Stack { get; private set; }

		public Int32 StackSize { get { return Stack != null ? Stack.Count : 0; } }

		public VerifiableTracker Verifier { get; private set; }

		// Set when the stack is underflowed
		public Boolean IsStackUnderflow { get; private set; }

		public Int32 ExpectedStackSize { get; private set; }

		// Set when stacks don't match during an incoming
		public Boolean IsStackMismatch { get; private set; }

		public Stack<List<TypeOnStack>> ExpectedStack { get; private set; }

		public Stack<List<TypeOnStack>> IncomingStack { get; private set; }

		// Set when types are dodge
		public Boolean IsTypeMismatch { get; private set; }

		public Int32? TransitionIndex { get; private set; }

		public Int32 StackIndex { get; private set; }

		public IEnumerable<TypeOnStack> ExpectedAtStackIndex { get; private set; }

		// Set when the stack was expected to be a certain size, but it wasn't
		public Boolean IsStackSizeFailure { get; private set; }

		public Label InvolvingLabel { get; private set; }

		public IEnumerable<TypeOnStack> ExpectedOnStack { get; private set; }

		public IEnumerable<TypeOnStack> ActuallyOnStack { get; private set; }

		public static VerificationResult Successful()
		{
			return new VerificationResult { Success = true };
		}

		public static VerificationResult Successful(VerifiableTracker verifier, Stack<List<TypeOnStack>> stack)
		{
			return new VerificationResult { Success = true, Stack = stack, Verifier = verifier };
		}

		public static VerificationResult FailureUnderflow(Label involving, Int32 expectedSize)
		{
			return
					new VerificationResult
					{
						Success = false,

						IsStackUnderflow = true,
						ExpectedStackSize = expectedSize,

						InvolvingLabel = involving
					};
		}

		public static VerificationResult FailureUnderflow(VerifiableTracker verifier, Int32 transitionIndex, Int32 expectedSize, Stack<List<TypeOnStack>> stack)
		{
			return
					new VerificationResult
					{
						Success = false,

						Verifier = verifier.Clone(),
						TransitionIndex = transitionIndex,

						IsStackUnderflow = true,
						ExpectedStackSize = expectedSize,
						Stack = stack
					};
		}

		public static VerificationResult FailureStackMismatch(VerifiableTracker verifier, Stack<List<TypeOnStack>> expected, Stack<List<TypeOnStack>> incoming)
		{
			return
					new VerificationResult
					{
						Success = false,

						Verifier = verifier.Clone(),

						IsStackMismatch = true,
						ExpectedStack = expected,
						IncomingStack = incoming
					};
		}

		public static VerificationResult FailureTypeMismatch(Label involving, List<TypeOnStack> expected, List<TypeOnStack> actual)
		{
			return
					new VerificationResult
					{
						Success = false,

						IsTypeMismatch = true,
						ExpectedOnStack = expected,
						ActuallyOnStack = actual
					};
		}

		public static VerificationResult FailureTypeMismatch(VerifiableTracker verifier, Int32 transitionIndex, Int32 stackIndex, IEnumerable<TypeOnStack> expectedTypes, Stack<List<TypeOnStack>> stack)
		{
			return
					new VerificationResult
					{
						Success = false,

						Verifier = verifier.Clone(),
						TransitionIndex = transitionIndex,

						IsTypeMismatch = true,
						StackIndex = stackIndex,
						ExpectedAtStackIndex = expectedTypes,
						Stack = stack
					};
		}

		public static VerificationResult FailureStackSize(VerifiableTracker verifier, Int32 transitionIndex, Int32 expectedSize)
		{
			return
					new VerificationResult
					{
						Success = false,

						Verifier = verifier.Clone(),
						TransitionIndex = transitionIndex,

						IsStackSizeFailure = true,
						ExpectedStackSize = expectedSize
					};
		}
	}
}